home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
usenet
/
sources
/
volume90
/
util
/
snap_1_4
/
part01
/
source
/
saveilbm.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-02-11
|
6KB
|
221 lines
/* Auto: make
*/
IMPORT BPTR SnapFile;
IMPORT BYTE TranspBuf[];
#define ID(a,b,c,d) ((a << 24L) | (b << 16L) | (c << 8L) | (d))
struct ckHdr {
LONG ChunkName;
LONG ChunkSize;
};
struct BitMapHeader
{
UWORD w,h;
WORD x,y;
UBYTE nPlanes;
UBYTE masking;
UBYTE compression;
UBYTE pad1;
UWORD transparentColor;
UBYTE xAspect, yAspect;
WORD pageWidth, pageHeight;
};
struct ckHdr FORM = {
ID('F','O','R','M'),
0L
};
LONG TYPE = ID('I','L','B','M');
struct ckHdr BMHD = {
ID('B','M','H','D'),
sizeof(struct BitMapHeader)
};
struct BitMapHeader BMHdr = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
struct ckHdr CAMG = {
ID('C','A','M','G'),
4L
};
ULONG ViewMode = NULL;
struct ckHdr CMAP = {
ID('C','M','A','P'),
0L
};
struct ckHdr BODY = {
ID('B','O','D','Y'),
0L
};
UBYTE *buf;
WORD bufcnt;
ULONG totalsize;
WORD bumpmode;
#define BUMP_CALC 1
#define BUMP_SAVE 2
WORD bump(cnt, dataptr, size)
WORD cnt;
UBYTE *dataptr;
WORD size;
{
REGISTER LONG tsize = size;
if (tsize) {
totalsize += tsize + 1; /* Don't forget the count-byte */
}
if (bumpmode == BUMP_CALC) { /* Just calculating? */
return 1; /* Don't do the save */
}
if (bufcnt + tsize + 1 >= 4096 || tsize == 0) {
if (Write(SnapFile, buf, (LONG)bufcnt) == -1L) {
return 0;
}
bufcnt = 0;
}
buf[bufcnt++] = cnt;
CopyMem((char *)dataptr, (char *)&buf[bufcnt], tsize);
bufcnt += tsize;
return 1;
}
ULONG WriteBody(BM)
struct BitMap *BM;
{
WORD scanline, plane;
REGISTER WORD bpr = BM->BytesPerRow;
REGISTER WORD i, j;
LONG offset = 0L;
REGISTER UBYTE data;
REGISTER UBYTE *bd;
totalsize = 0L;
if (!(buf = AllocMem(4096L, MEMF_PUBLIC))) {
return NULL;
}
bufcnt = 0;
for (scanline = 0; scanline < BM->Rows; ++scanline) {
for (plane = 0; plane < BM->Depth; ++plane) {
bd = BM->Planes[plane]+offset;
i = 1;
j = bpr - 1;
data = bd[0];
while (j) {
if (bd[i] == data) { /* Equal bytes? */
--i; /* First equal byte */
if (i > 0) { /* Old "random" data to save */
if (!bump((WORD)(i - 1), bd, i)) {
return NULL;
}
}
bd = &bd[i]; /* Start of equal bytes */
i = 2; /* 0 & 1 is equal */
--j;
while (i < 128 && j && bd[i] == data) {
++i;
--j;
}
if (!bump((WORD)-(i - 1), &bd[i - 1], 1)) {
return NULL;
}
goto new_block;
} else { /* Not equal. Check block range */
if (i == 128) { /* Block limit */
if (!bump((WORD)(i - 1), bd, i)) {
return NULL;
}
new_block:
bd = &bd[i]; /* Start new block */
i = 0;
if (j == 0) {
break;
}
}
}
/* Different byte or a new start */
data = bd[i]; /* New possible equal */
next_byte:
++i;
--j;
}
if (i != 0) { /* Data to save */
if (!bump((WORD)(i - 1), bd, i)) {
return NULL;
}
}
}
offset += BM->BytesPerRow;
}
if (!bump(0, NULL, 0)) { /* Flush any bytes left if the buffer */
return NULL;
}
FreeMem(buf, 4096L);
return totalsize;
}
WORD SaveGS(GS)
struct GfxSnap *GS;
{
ULONG BODYPos;
UBYTE *oldtitle;
oldtitle = GS->window->Title;
SetWindowTitles(GS->window, "Saving...", NULL);
bumpmode = BUMP_SAVE;
BMHdr.w = GS->BM.BytesPerRow * 8;
BMHdr.h = GS->height;
BMHdr.x = BMHdr.y = 0;
BMHdr.nPlanes = GS->depth;
BMHdr.masking = 0;
BMHdr.compression = 1;
BMHdr.transparentColor = dectoint(TranspBuf);
BMHdr.xAspect = BMHdr.xAspect = 1;
BMHdr.pageWidth = GS->pagew;
BMHdr.pageHeight = GS->pageh;
ViewMode = GS->viewmode;
CMAP.ChunkSize = (LONG)3 * (GS->viewmode & HAM ? 16 : 1L << GS->depth);
if (Write(SnapFile, (char *)&FORM,
(LONG)(sizeof(FORM) + sizeof(TYPE) +
sizeof(BMHD) + sizeof(BMHdr) +
sizeof(CAMG) + sizeof(ViewMode) +
sizeof(CMAP))) == -1L) {
return 0;
}
if (Write(SnapFile, (char *)&GS->rgb[0], CMAP.ChunkSize) == -1L) {
return 0;
}
BODYPos = Seek(SnapFile, 0L, OFFSET_CURRENT);
if (Write(SnapFile, (char *)&BODY, (LONG)sizeof(BODY)) == -1L) {
return 0;
}
if (!(BODY.ChunkSize = WriteBody(&GS->BM))) {
return 0;
}
FORM.ChunkSize = BODYPos - sizeof(FORM) + sizeof(BODY) + BODY.ChunkSize;
if (FORM.ChunkSize & 1) { /* Odd size */
if (Write(SnapFile, "X", 1L) == -1L) {
return 0;
}
++FORM.ChunkSize;
}
Seek(SnapFile, 0L, OFFSET_BEGINNING);
Write(SnapFile, (char *)&FORM, (LONG)sizeof(FORM));
Seek(SnapFile, BODYPos, OFFSET_BEGINNING);
Write(SnapFile, (char *)&BODY, (LONG)sizeof(BODY));
SetWindowTitles(GS->window, oldtitle, NULL);
return 1;
}